from nmj.core.constants import REGEXP_SHOW_WITH_EPISODE, \
	REGEXP_SHOW_WITH_SEASON_EPISODE, REGEXP_SHOW_WITH_SEASON, REGEXP_MOVIES
from nmj.core.main import NMJUpdater
from nmj.scanners.regexp_based_scanner import RegexpBasedScanner, TVShowCleaner, \
	MovieCleaner
from nmj.scanners.tmdb import TMDBMovie
from nmj.sqlite.tables import ALL_TABLES, DbVersion, ScanDirs, ScanSystem, Show, \
	Video, VideoAttr, VideoGroup, VideoGroupName, VideoSynopsis
from tempfile import mkdtemp
import logging
import os
import pprint
import shutil
import unittest


_LOGGER = logging.getLogger(__name__)

class TVShowDummyScanner(object):
	def search(self, string, season=None, episode=None, **_kwargs):
		_LOGGER.info("TVShow search for %s", string)

class MovieDummyScanner(object):
	def __init__(self):
		self.movies = {}
		self.results_from_id = {}

	def create_movie(self, name, posters=None, fanarts=None, **kwargs):
		return TMDBMovie(
				tmdb_id=kwargs.get("id", "123456"),
				imdb_id=kwargs.get("id", "123456"),
				title=kwargs.get("title", "title %s" % name),
				synopsis=kwargs.get("overview", "movie %s synopsis" % name),
				short_synopsis=kwargs.get("short_synopsis", "movie %s short synopsis" % name),
				posters=posters or [],
				fanarts=fanarts or [],
				genres=kwargs.get("categories", {"genre" : {}}).get("genre", {}).keys(),
				cast=kwargs.get("cast", {}),
				rating=float(kwargs.get("rating", 0)),
			)

	def add_movie(self, name, posters=None, fanarts=None, **kwargs):
		movie = self.create_movie(name, posters=posters, fanarts=fanarts, **kwargs)
		if self.movies.has_key(name):
			self.movies[name].append(movie)
		else:
			self.movies[name] = [movie,]

	def add_movie_from_id_results(self, movie_id, *results):
		if self.results_from_id.has_key(movie_id):
			self.results_from_id[movie_id].extend(results)
		else:
			self.results_from_id[movie_id] = results

	def search(self, string, **_kwargs):
		_LOGGER.info("Movie search for %s", string)
		movies = self.movies.get(string, [])
		for movie in movies:
			movie.get_media = self.get_media(movie.tmdb_id)
		return movies

	def get_media(self, movie_id, get_first_result=True):
		_LOGGER.info("MovieDummyScanner return fetch functor")
		def fetch():
			results = self.results_from_id.get(movie_id, None) or []
			_LOGGER.info("MovieDummyScanner return get_media results %s", results)
			if results and get_first_result:
				return results[0]
			return results
		return fetch

class DBCreation_TestCase(unittest.TestCase):
	def setUp(self):
		self.base_dir = None

	def tearDown(self):
		if self.base_dir:
			shutil.rmtree(self.base_dir)

	def prepare_movie_library(self, movie_number=10):
		self.base_dir = mkdtemp()
		for rank in range(movie_number):
			file(os.path.join(self.base_dir, "movie%d.avi"%rank), "w+").close()
		return self.base_dir

	def remove_file(self, filename):
		os.remove(os.path.join(self.base_dir, filename))

	def prepare_nmj_with_one_library(self, movie_number=10):
		self.nmj = NMJUpdater()
		self.tv_show_with_episode_scanner = TVShowDummyScanner()
		self.tv_show_with_season_episode_scanner = TVShowDummyScanner()
		self.tv_show_with_season_scanner = TVShowDummyScanner()
		self.movie_scanner = MovieDummyScanner()
		self.nmj.add_library(self.prepare_movie_library(movie_number=movie_number), RegexpBasedScanner(
			(REGEXP_SHOW_WITH_EPISODE, self.tv_show_with_episode_scanner, TVShowCleaner(), "tv_show_with_episode_scanner"),
			(REGEXP_SHOW_WITH_SEASON_EPISODE, self.tv_show_with_season_episode_scanner, TVShowCleaner(), "tv_show_with_season_episode_scanner"),
			(REGEXP_SHOW_WITH_SEASON, self.tv_show_with_season_scanner, TVShowCleaner(), "tv_show_with_season_scanner"),
			(REGEXP_MOVIES, self.movie_scanner, MovieCleaner(), "movie_scanner"),
		))

	def check_db_DbVersion(self, library):
		items = library.get_all(DbVersion)
		self.failUnlessEqual(1, len(items))
		self.failUnlessEqual("1.8.0", items[0].version)

	def check_db_ScanDirs(self, library):
		items = library.get_all(ScanDirs)
		self.failUnlessEqual(1, len(items))

	def check_db_ScanSystem(self, library):
		items = library.get_all(ScanSystem)
		self.failUnlessEqual(2, len(items))
		self.failUnlessEqual("RUNNING_STATUS", items[0].type)
		self.failUnlessEqual("0", items[0].value)
		self.failUnlessEqual("UPDATING_STAGE", items[1].type)
		self.failUnlessEqual("5", items[1].value)

	def check_db_empty_table(self, library, table):
		self.failUnlessEqual(0, len(library.get_all(table)), "Table %s not empty" % table.__name__)

	def check_all_db_tables(self, **checkers):
		for library in self.nmj.libraries:
			self.check_library_db(library, **checkers)

	def check_library_db(self, library, **checkers):
		for table in ALL_TABLES:
			if checkers.has_key(table.__name__):
				checkers[table.__name__](library)
			else:
				getattr(self, "check_db_%s" % table.__name__, lambda x: self.check_db_empty_table(x, table))(library)

	def check_movie_insertion(self, lib, *movie_name):
		def check_Show(library):
			items = library.get_all(Show)
			self.failUnlessEqual(len(movie_name), len(items))
		def check_Video(library):
			items = library.get_all(Video)
			self.failUnlessEqual(len(movie_name), len(items))
		def check_VideoAttr(library):
			items = library.get_all(VideoAttr)
			self.failUnlessEqual(len(movie_name), len(items))
		def check_VideoGroup(library):
			items = library.get_all(VideoGroup)
			self.failUnlessEqual(len(movie_name), len(items))
		def check_VideoGroupName(library):
			items = library.get_all(VideoGroupName)
			self.failUnlessEqual(len(movie_name), len(items))
		def check_VideoSynopsis(library):
			items = library.get_all(VideoSynopsis)
			self.failUnlessEqual(len(movie_name), len(items))
		self.check_library_db(
			lib,
			Video=check_Video,
			Show=check_Show,
			VideoAttr=check_VideoAttr,
			VideoGroup=check_VideoGroup,
			VideoGroupName=check_VideoGroupName,
			VideoSynopsis=check_VideoSynopsis,
		)

	def test_01a(self):
		"Scan for movies from nothing (DB creation), no movies case"
		self.prepare_nmj_with_one_library(movie_number=0)
		report = self.nmj.update()[0]
		self.failIf(report.get_new_media())
		self.failIf(report.get_already_known_media())
		self.failIf(report.get_media_not_found())
		self.check_all_db_tables()

	def test_01b(self):
		"Scan for movies from nothing (DB creation) movies files but not found on scanner case"
		self.prepare_nmj_with_one_library(movie_number=10)
		report = self.nmj.update()[0]
		self.failIf(report.get_new_media())
		self.failIf(report.get_already_known_media())
		self.failUnlessEqual(10, len(report.get_media_not_found()))
		self.check_all_db_tables()

	def test_02a(self):
		"Scan for movies from nothing (DB creation) movies files found on scanner case"
		movie_name = "movie1"
		movie_id = "movie1 id"
		self.prepare_nmj_with_one_library(movie_number=10)
		self.movie_scanner.add_movie(movie_name, id=movie_id)
		self.movie_scanner.add_movie_from_id_results(
			movie_id, self.movie_scanner.create_movie(movie_name, posters=None, fanarts=None, id=movie_id)
		)
		report = self.nmj.update()[0]
		self.failUnlessEqual(1, len(report.get_new_media()))
		self.failIf(report.get_already_known_media())
		self.failUnlessEqual(9, len(report.get_media_not_found()))
		self.check_movie_insertion(self.nmj.libraries[0], movie_name)

	def test_03a(self):
		"Scan for movies from nothing (DB creation) movies file found on scanner, and then removed on second scan"
		movie_name = "movie1"
		movie_id = "movie1 id"
		self.prepare_nmj_with_one_library(movie_number=10)
		self.movie_scanner.add_movie(movie_name, id=movie_id)
		self.movie_scanner.add_movie_from_id_results(
			movie_id, self.movie_scanner.create_movie(movie_name, posters=None, fanarts=None, id=movie_id)
		)
		report = self.nmj.update()[0]
		self.failUnlessEqual(1, len(report.get_new_media()))
		self.failIf(report.get_already_known_media())
		self.failUnlessEqual(9, len(report.get_media_not_found()))
		self.check_movie_insertion(self.nmj.libraries[0], movie_name)
		self.remove_file("%s.avi" % movie_name)
		self.nmj.clean()
		self.check_all_db_tables()

if __name__ == "__main__":
	logging.basicConfig(format='%(asctime)-15s [%(levelname)s] <%(name)s> %(message)s', level=logging.ERROR)
	unittest.main()


